package com.xiaogang.minio.service;

import cn.hutool.cache.impl.TimedCache;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.xiaogang.minio.utils.FileUtils;
import com.xiaogang.minio.utils.Minio;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @ProjectName : minio
 * @作者 : 侯小刚
 * @描述 :
 * @创建日期 : 2023/7/26 18:23
 */
@Component
public class MinioUtils {

    @Autowired
    private Minio minio;

    private static final String SERVER_DATE_URL = "http://172.17.164.80:9010/api/api/client/v2/getSystemTime";

    /**
     * 文件上传
     * @param inputStream 文件流
     * @param fileName 文件名
     * @return 文件路径
     */
    public String fileUpload(InputStream inputStream, String fileName) {
        //它的SDK源码里也会自动转换
        int DEFAULT_PARTSIZE  = 10 * 1024 * 1024;
        String endpoint = minio.getEndpoint();
        String accessKeyId = minio.getAccessKeyId();
        String accessKeySecret = minio.getAccessKeySecret();
        String bucketName = minio.getBucketName();
        fileName = FileUtils.dealMinioFileName(fileName);
        try {
            String date = null;
            // 从spring容器中取出 myCache 对象
            TimedCache myCacheManager = SpringUtil.getBean("myCacheManager");
            if(null != myCacheManager.get("sys_date")) {
                String sys_date = (String) myCacheManager.get("sys_date");
                if(StringUtils.hasLength(sys_date)) {
                    date = sys_date;
                }
            } else {
                String body = HttpRequest.get(SERVER_DATE_URL).execute().body();
                String data = JSONUtil.parseObj(body).getStr("data");
                if(StringUtils.hasLength(data)) {
                    date = data;
                    myCacheManager.put("sys_date",data);
                }
            }


            MinioSelfClient minioClient = new MinioSelfClient(endpoint, accessKeyId, accessKeySecret);
            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists(bucketName,date);
            if(!isExist) {
                // 创建一个桶
                minioClient.makeBucket(bucketName);
            }
            int fileSize = inputStream.available();

            PutObjectOptions putObjectOptions = new PutObjectOptions(fileSize, DEFAULT_PARTSIZE);
            // 使用putObject上传一个文件到存储桶中。
            minioClient.putObject(bucketName, fileName, inputStream, putObjectOptions,date);

            return minioClient.getObjectUrl(bucketName, fileName);
        } catch (InvalidBucketNameException e) {
            e.printStackTrace();
            throw new RuntimeException("非法存储名称");
        } catch (IOException e){
            throw new RuntimeException("连接文件服务异常");
        } catch (ErrorResponseException e){
            throw new RuntimeException("执行失败:"+e.getMessage());
        } catch (InternalException e){
            throw new RuntimeException("内部异常");
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("文件上传失败！"+e.getMessage());
        }
    }

    /**
     * 获取文件
     * @param fileName
     * @return
     */
    public InputStream getFileInputStream(String fileName){
        //构建客户端信息
        String endpoint = minio.getEndpoint();
        String accessKeyId = minio.getAccessKeyId();
        String accessKeySecret = minio.getAccessKeySecret();
        String bucketName = minio.getBucketName();
        try {
            MinioClient minioClient = new MinioClient(endpoint, accessKeyId, accessKeySecret);
            return minioClient.getObject(bucketName,fileName);
        } catch (InvalidBucketNameException e) {
            e.printStackTrace();
            throw new RuntimeException("不合法的存储桶名称");
        } catch (InsufficientDataException e) {
            e.printStackTrace();
            throw new RuntimeException("在读到相应length之前就得到一个EOFException");
        } catch (ErrorResponseException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务执行失败");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("连接文件服务异常");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("找不到相应的签名算法");
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务账号密码错误");
        } catch (InvalidResponseException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务无响应");
        } catch (InternalException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务内部错误");
        }catch (Exception e){
            throw new RuntimeException("文件URL获取失败，"+e.getMessage());
        }
    }

    /**
     * 获取文件url
     * @param fileName
     * @return
     */
    public String getFileUrl(String fileName){
        //构建客户端信息
        String endpoint = minio.getEndpoint();
        String accessKeyId = minio.getAccessKeyId();
        String accessKeySecret = minio.getAccessKeySecret();
        String bucketName = minio.getBucketName();
        try {
            MinioClient minioClient = new MinioClient(endpoint, accessKeyId, accessKeySecret);
            return minioClient.getObjectUrl(bucketName, fileName);
        } catch (InvalidBucketNameException e) {
            e.printStackTrace();
            throw new RuntimeException("不合法的存储桶名称");
        } catch (InsufficientDataException e) {
            e.printStackTrace();
            throw new RuntimeException("在读到相应length之前就得到一个EOFException");
        } catch (ErrorResponseException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务执行失败");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("连接文件服务异常");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("找不到相应的签名算法");
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务账号密码错误");
        } catch (InvalidResponseException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务无响应");
        } catch (InternalException e) {
            e.printStackTrace();
            throw new RuntimeException("文件服务内部错误");
        }catch (Exception e){
            throw new RuntimeException("文件URL获取失败，"+e.getMessage());
        }
    }

    /**
     * 删除文件
     * @param name
     */
    public void deleteFile(String name) {
        //构建客户端信息
        String endpoint = minio.getEndpoint();
        String accessKeyId = minio.getAccessKeyId();
        String accessKeySecret = minio.getAccessKeySecret();
        String bucketName = minio.getBucketName();
        try{
            MinioClient minioClient = new MinioClient(endpoint, accessKeyId, accessKeySecret);
            minioClient.removeObject(bucketName, name);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 下载文件
     * @param path
     * @param customName
     * @return
     */
    public String downLoadFile(String path,String customName) {
        InputStream fileInputStream = getFileInputStream(path);
        if(fileInputStream == null){
            return null;
        }
        String fileName = StringUtils.isEmpty(customName)?path.substring(path.lastIndexOf("/") + 1) : customName;
        String property = System.getProperty("user.dir");
        String filePath = property + File.separator + FileUtils.dealFileName(fileName);
        try {
            saveFile(fileInputStream, filePath);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return filePath;
    }

    /**
     * 保存文件到本地
     * @param inputStream
     * @param path
     */
    private void saveFile(InputStream inputStream, String path) {
        OutputStream os = null;
        try {
            // 2、保存到临时文件
            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            // 输出的文件流保存到本地文件
            os = new FileOutputStream(path);
            // 开始读取
            while ((len = inputStream.read(bs)) != -1) {
                os.write(bs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 完毕，关闭所有链接
            try {
                os.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}
